package com.example.demo.component.docker;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.component.docker.bean.create_container_param;
import com.spotify.docker.client.DefaultDockerClient;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.LogStream;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @ClassName docker_client
 * @Description
 * @date 2022/11/7 9:35
 * @Author yanceysong
 * @Version 1.0
 */
public class docker_client {

    protected static final String DOCKER_REPOSITORY_ADDRESS = "172.21.2.26";
    private final DockerClient docker;

    public docker_client(String ip, String port) {
        docker = DefaultDockerClient.builder()
                .uri(URI.create("http://" + ip + ":" + port))
//            .dockerCertificates(new DockerCertificates(Paths.get("/Users/rohan/.docker/boot2docker-vm/")))
                .build();
    }

    /**
     * 发送get请求
     *
     * @param url   请求URL
     * @param param 请求参数 key:value url携带参数 或者无参可不填
     * @return 请求结果
     */
    public static String doGet(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();
            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);
            // 执行请求
            response = httpClient.execute(httpGet);

            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static void main(String[] args) {
        docker_client docker_client = docker_client_factory.get_docker_client("172.22.2.74");
        List<Container> runtime_containers = docker_client.get_runtime_containers();
//        List<String> strings = list_repository_image();
        System.out.println("delete_repository_image(\"ap\", \"v0.8\") = " + delete_repository_image("ap", "v0.8"));
//        System.out.println(strings);
    }
    /**
     * 获取正在运行的容器
     *
     * @return 所有的容器信息
     */
    public List<Container> get_runtime_containers() {
        try {
            return docker.listContainers();
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从私有镜像仓库查询某个镜像的版本号，按照特定的规则进行排序后返回
     *
     * @param image_name 镜像的名字
     * @param limit      限制显示的数量
     * @return 结果
     */
    public static List<String> list_repository_image_tag(String image_name, int limit) {
        String url = "http://172.21.2.26:5000/v2/" + image_name + "/tags/list";
        JSONObject docker_image_info = JSONObject.parseObject(doGet(url, null));
        if (docker_image_info == null || docker_image_info.toString().equals("") || docker_image_info.get("errors") != null) {
            ArrayList<String> tag_list = new ArrayList<>();
            tag_list.add("null");
            return tag_list;
        }
        ArrayList<String> tag_raw = (ArrayList<String>) JSONObject.parseArray(docker_image_info.getJSONArray("tags").toString(), String.class);
        tag_raw.sort((o1, o2) -> {
            String s1 = o1.startsWith("v") ? o1.substring(1).split("-")[0] : o1.split("-")[0];
            String s2 = o2.startsWith("v") ? o2.substring(1).split("-")[0] : o2.split("-")[0];
            //先比较整数部分
            int s1_int = Integer.parseInt(s1.split("\\.")[0]);
            int s2_int = Integer.parseInt(s2.split("\\.")[0]);
            if (s1_int != s2_int) return s2_int - s1_int;
            //整数部分相同再比较小数部分
            int s1_decimals = Integer.parseInt(s1.split("\\.")[1]);
            int s2_decimals = Integer.parseInt(s2.split("\\.")[1]);
            return s2_decimals - s1_decimals;

        });
        return tag_raw.size() > limit ? tag_raw.subList(0, limit) : tag_raw;
    }

    /**
     * 删除镜像仓库的镜像
     *
     * @param image_name 镜像名称
     * @param tag        镜像版本
     * @return 删除结果
     */
    public static boolean delete_repository_image(String image_name, String tag) {
        String delete_url = "http://" + DOCKER_REPOSITORY_ADDRESS + ":5000/v2/" + image_name + "/manifests/" + docker_client_util.get_digest(image_name, tag);
        ArrayList<String> commands = new ArrayList<>();
        commands.add("curl -X DELETE " + delete_url);
        return !JSONObject.parseObject(docker_client_util.execute(commands)).containsKey("errors");
    }

    /**
     * 展示镜像仓库中当前有哪些镜像
     *
     * @return 镜像名称集合
     */
    public static List<String> list_repository_image() {
        String url = "http://" + DOCKER_REPOSITORY_ADDRESS + ":5000/v2/_catalog";
        JSONObject image_info = JSONObject.parseObject(doGet(url, null));
        return JSONObject.parseArray(image_info.getJSONArray("repositories").toString(), String.class);
    }

    /**
     * 从私有镜像仓库查询某个镜像的版本号，按照特定的规则进行排序返回
     *
     * @param image_name 镜像的名字
     * @return 结果
     */
    public static List<String> list_repository_image_tag(String image_name) {
        return list_repository_image_tag(image_name, 10);
    }

    /**
     * 构建镜像
     *
     * @param Dockerfile_path dockerfile路径
     * @param image_name      名字
     * @return 返回构建成功的镜像的id
     */
    public String build_image(String Dockerfile_path, String image_name) {
        final AtomicReference<String> imageIdFromMessage = new AtomicReference<>();
        try {
            return docker.build(
                    Paths.get(Dockerfile_path), image_name, message -> {
                        final String imageId = message.buildImageId();
                        if (imageId != null) {
                            imageIdFromMessage.set(imageId);
                        }
                    });
        } catch (DockerException | InterruptedException | IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据容器id在容器id内执行命令
     *
     * @param container_id 容器id
     * @param command      指令
     * @return 返回执行结果
     */
    public String exec_command(String container_id, String command) {
        try {
            final String[] commands = {"sh", "-c", command};
            final ExecCreation execCreation = docker.execCreate(
                    container_id, commands, DockerClient.ExecCreateParam.attachStdout(),
                    DockerClient.ExecCreateParam.attachStderr());
            final LogStream output = docker.execStart(execCreation.id());
            return output.readFully();
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 关闭连接
     */
    protected void close() {
        docker.close();
    }

    /**
     * 获取所有的容器信息
     *
     * @return 所有的容器信息
     */
    public List<Container> get_all_containers() {
        try {
            return docker.listContainers(DockerClient.ListContainersParam.allContainers());
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取容器日志
     *
     * @param container_id 容器id
     * @return 日志内容
     */
    public String get_logs(String container_id) {
        final String logs;
        try (LogStream stream = docker.logs(container_id, DockerClient.LogsParam.stdout(), DockerClient.LogsParam.stderr())) {
            logs = stream.readFully();
            return logs;
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 列出容器内运行的进程
     *
     * @param container_id 容器id
     * @return 运行结果
     */
    public TopResults get_top_result(String container_id) {
        try {
            return docker.topContainer(container_id, "ps_args");
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据config 创建一个容器
     *
     * @param config build config
     * @return 创建的容器（可获取id）
     */
    public ContainerCreation create_container(create_container_param config) {
        try {
            //映射端口
            HostConfig.Builder builder = HostConfig.builder().portBindings(config.getPortBindings());
            //映射挂载
            List<create_container_param.path_map> path_maps = config.getPath_maps();
            for (create_container_param.path_map path_map : path_maps) {
                builder = builder.appendBinds(HostConfig.Bind.from(path_map.getHost_path())
                        .to(path_map.getContainer_path()).readOnly(path_map.getRead_only()).build());
            }
            final ContainerConfig containerConfig =
                    ContainerConfig.builder()
                            .image(config.getImage_name() + ":" + config.getImage_version())
//                            .volumes("/foo")   // This volume will not mount any host directory
                            .hostConfig(builder.build())
                            .build();
            //创建容器
            return docker.createContainer(containerConfig, config.getContainer_name());
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 检查容器文件系统上的更改
     *
     * @param container_id 容器id
     * @return 更改结果
     */
    public List<ContainerChange> inspect_container_changes(String container_id) {
        try {
            return docker.inspectContainerChanges(container_id);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据id启动一个容器
     *
     * @param container_id 容器的id
     */
    public void start_container(String container_id) {
        try {
            docker.startContainer(container_id);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止一个容器
     *
     * @param container_id 容器id
     */
    public void stop_container(String container_id) {
        try {
            //1s之后关闭
            docker.stopContainer(container_id, 1);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 重启一个容器
     *
     * @param container_id 容器id
     */
    public void restart_container(String container_id) {
        try {
            docker.restartContainer(container_id);
        } catch (DockerException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 重启一个容器,等待时间
     *
     * @param container_id 容器id
     */
    public void restart_container(String container_id, int seconds) {
        try {
            docker.restartContainer(container_id, seconds);
        } catch (DockerException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 强制停止一个容器
     *
     * @param container_id 容器id
     */
    public void kill_container(String container_id) {
        try {
            docker.killContainer(container_id);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除一个容器
     *
     * @param container_id 容器id
     */
    public void remove_container(String container_id) {
        try {
            docker.removeContainer(container_id);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取所有镜像
     *
     * @return 镜像集合
     */
    public List<Image> get_images() {
        try {
            return docker.listImages(DockerClient.ListImagesParam.allImages());
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据镜像id获取这个镜像的所有版本
     *
     * @param images_id 镜像id
     * @return 该镜像的所有历史版本
     */
    public List<ImageHistory> get_image_history(String images_id) {
        try {
            return docker.history("imageID");
        } catch (InterruptedException | DockerException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 推送镜像
     *
     * @param image_id 镜像id
     */
    public void push_image(String image_id) {
        try {
            docker.push(image_id);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 拉取镜像
     *
     * @param image 镜像名字
     */
    public void pull_image(String image) {
        try {
            docker.pull(image);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 为镜像tag
     *
     * @param tag_name   tag
     * @param image_name image_name
     */
    public void tag_image(String tag_name, String image_name) {
        try {
            docker.tag(tag_name, image_name);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除一个镜像
     *
     * @param images_id 镜像id
     */
    public void remove_image(String images_id) {
        try {
            docker.removeImage(images_id);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据关键字搜索镜像
     *
     * @param image_keyword 镜像关键字
     * @return 搜索结果
     */
    public List<ImageSearchResult> search_images_by_local(String image_keyword) {
        try {
            return docker.searchImages(image_keyword);
        } catch (DockerException | InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
